#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <cerrno>
#include <pthread.h>
#include <signal.h>
#include <dirent.h>
#include <ctype.h>
#include <inttypes.h>  // 添加这个头文件用于PRId64

// 包含生成的HTML文件
#include "video_player.h"

char program_dir[PATH_MAX];

// 忽略SIGPIPE信号，防止写入已关闭的socket导致程序退出
void setup_signal_handlers() {
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGPIPE, &sa, NULL);
}

// 改进的获取程序目录函数
void init_program_directory() {
    // 方法1: 通过 /proc/self/exe 获取程序路径
    ssize_t count = readlink("/proc/self/exe", program_dir, sizeof(program_dir) - 1);
    if (count != -1) {
        program_dir[count] = '\0';
        char* last_slash = strrchr(program_dir, '/');
        if (last_slash != NULL) {
            *last_slash = '\0';
        }
        printf("Program directory (from /proc/self/exe): %s\n", program_dir);
        return;
    }
    
    // 方法2: 如果方法1失败，使用当前工作目录
    if (getcwd(program_dir, sizeof(program_dir)) != NULL) {
        printf("Program directory (from getcwd): %s\n", program_dir);
        return;
    }
    
    // 方法3: 最后备选
    strcpy(program_dir, ".");
    printf("Program directory (fallback): %s\n", program_dir);
}

void Usage() {
    printf("usage: ./server [ip] [port]\n");
}

// 安全的写入函数，处理SIGPIPE信号
ssize_t safe_write(int fd, const void *buf, size_t count) {
    ssize_t result;
    do {
        result = write(fd, buf, count);
    } while (result == -1 && errno == EINTR);
    
    return result;
}

// URL解码函数
void url_decode(char* str) {
    char *src = str, *dst = str;
    while (*src) {
        if (*src == '%' && isxdigit(src[1]) && isxdigit(src[2])) {
            // 处理 %20 等编码
            char hex[3] = {src[1], src[2], 0};
            *dst = (char)strtol(hex, NULL, 16);
            src += 2;
        } else if (*src == '+') {
            *dst = ' ';
        } else {
            *dst = *src;
        }
        dst++;
        src++;
    }
    *dst = '\0';
}

// 获取视频文件列表
void send_video_list(int client_fd) {
    char videos_dir[PATH_MAX * 2];
    snprintf(videos_dir, sizeof(videos_dir), "%s/videos", program_dir);
    
    DIR *dir = opendir(videos_dir);
    if (dir == NULL) {
        const char *error = "HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\n\r\n{\"error\":\"Cannot open videos directory\"}";
        safe_write(client_fd, error, strlen(error));
        return;
    }
    
    // 构建JSON响应
    char json_buffer[64 * 1024] = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n[";
    int first = 1;
    
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG) {
            const char *name = entry->d_name;
            if (strstr(name, ".mp4") || strstr(name, ".webm") || strstr(name, ".ogg") || 
                strstr(name, ".ogv") || strstr(name, ".mov") || strstr(name, ".avi") || strstr(name, ".mkv")) {
                if (!first) {
                    strcat(json_buffer, ",");
                }
                strcat(json_buffer, "\"");
                strcat(json_buffer, name);
                strcat(json_buffer, "\"");
                first = 0;
            }
        }
    }
    
    strcat(json_buffer, "]");
    closedir(dir);
    
    safe_write(client_fd, json_buffer, strlen(json_buffer));
    printf("Thread %lu: Sent video list\n", pthread_self());
}

// 支持范围请求的视频传输函数
void send_video_with_range_support(int client_fd, const char* file_path, const char* content_type, const char* range_header) {
    printf("Thread %lu: Sending video with range support: %s\n", pthread_self(), file_path);
    
    struct stat st;
    if (stat(file_path, &st) != 0) {
        printf("Thread %lu: File not found: %s\n", pthread_self(), file_path);
        const char *not_found = "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\n\r\nFile not found";
        safe_write(client_fd, not_found, strlen(not_found));
        return;
    }
    
    int file_fd = open(file_path, O_RDONLY);
    if (file_fd < 0) {
        printf("Thread %lu: Cannot open file: %s\n", pthread_self(), file_path);
        const char *error = "HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\nCannot open file";
        safe_write(client_fd, error, strlen(error));
        return;
    }
    
    // 处理范围请求
    if (range_header != NULL && strstr(range_header, "bytes=") != NULL) {
        // 解析范围请求
        long long start = 0, end = st.st_size - 1;
        sscanf(range_header, "bytes=%lld-%lld", &start, &end);
        
        // 范围有效性检查
        if (start < 0) start = 0;
        if (end >= st.st_size) end = st.st_size - 1;
        if (start > end) {
            start = 0;
            end = st.st_size - 1;
        }
        
        long long file_size = st.st_size;
        long long range_size = end - start + 1;
        
        // 修复警告：使用正确的格式说明符
        printf("Thread %lu: Range request: %lld-%lld (%lld bytes)\n", 
               pthread_self(), start, end, range_size);
        
        // 发送206部分内容响应
        char header[512];
        snprintf(header, sizeof(header),
            "HTTP/1.1 206 Partial Content\r\n"
            "Content-Type: %s\r\n"
            "Content-Range: bytes %lld-%lld/%lld\r\n"
            "Content-Length: %lld\r\n"
            "Accept-Ranges: bytes\r\n"
            "Connection: close\r\n"
            "\r\n", content_type, start, end, file_size, range_size);
        
        if (safe_write(client_fd, header, strlen(header)) < 0) {
            close(file_fd);
            return;
        }
        
        // 定位到指定位置
        lseek(file_fd, start, SEEK_SET);
        
        // 发送指定范围的数据
        char buffer[64 * 1024];
        long long remaining = range_size;
        long long total_sent = 0;
        
        while (remaining > 0) {
            size_t to_read = (remaining < sizeof(buffer)) ? remaining : sizeof(buffer);
            ssize_t bytes_read = read(file_fd, buffer, to_read);
            
            if (bytes_read <= 0) break;
            
            ssize_t bytes_written = safe_write(client_fd, buffer, bytes_read);
            if (bytes_written < 0) break;
            
            remaining -= bytes_written;
            total_sent += bytes_written;
            
            usleep(1000); // 小延迟
        }
        
        // 修复警告：使用正确的格式说明符
        printf("Thread %lu: Sent range: %lld bytes\n", pthread_self(), total_sent);
    } else {
        // 没有范围请求，发送整个文件
        long long file_size = st.st_size;
        printf("Thread %lu: Sending entire file: %lld bytes\n", pthread_self(), file_size);
        
        char header[512];
        snprintf(header, sizeof(header),
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: %s\r\n"
            "Content-Length: %lld\r\n"
            "Accept-Ranges: bytes\r\n"
            "Connection: close\r\n"
            "\r\n", content_type, file_size);
        
        if (safe_write(client_fd, header, strlen(header)) < 0) {
            close(file_fd);
            return;
        }
        
        // 发送整个文件
        char buffer[64 * 1024];
        ssize_t bytes_read;
        long long total_sent = 0;
        
        while ((bytes_read = read(file_fd, buffer, sizeof(buffer))) > 0) {
            ssize_t bytes_written = safe_write(client_fd, buffer, bytes_read);
            if (bytes_written < 0) break;
            total_sent += bytes_written;
            usleep(1000);
        }
        
        printf("Thread %lu: Sent entire file: %lld bytes\n", pthread_self(), total_sent);
    }
    
    close(file_fd);
}

// 客户端处理函数
void* handle_client(void* arg) {
    int client_fd = *(int*)arg;
    free(arg);
    
    char input_buf[1024 * 10] = {0};
    ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);
    if (read_size < 0) {
        perror("read");
        close(client_fd);
        return NULL;
    }
    
    // 检查是否读取到数据
    if (read_size == 0) {
        printf("Thread %lu: Client disconnected immediately\n", pthread_self());
        close(client_fd);
        return NULL;
    }
    
    printf("[Request from thread %lu] %s", pthread_self(), input_buf);
    
    // 处理视频列表请求
    if (strstr(input_buf, "GET /list ") != NULL) {
        send_video_list(client_fd);
    }
    // 处理视频文件请求
    else if (strstr(input_buf, "GET /videos/") != NULL) {
        char *start = strstr(input_buf, "GET /videos/") + 12;
        char *end = strchr(start, ' ');
        if (end != NULL) {
            char video_file[256] = {0};
            size_t filename_len = end - start;
            if (filename_len < sizeof(video_file)) {
                strncpy(video_file, start, filename_len);
                video_file[filename_len] = '\0';
                
                // URL解码
                url_decode(video_file);
                
                char full_path[PATH_MAX * 2];
                snprintf(full_path, sizeof(full_path), "%s/videos/%s", program_dir, video_file);
                
                printf("Thread %lu: Video request: %s -> %s\n", pthread_self(), video_file, full_path);
                
                // 确定内容类型
                const char *content_type = "video/mp4";
                if (strstr(video_file, ".webm")) {
                    content_type = "video/webm";
                } else if (strstr(video_file, ".ogg") || strstr(video_file, ".ogv")) {
                    content_type = "video/ogg";
                } else if (strstr(video_file, ".mov")) {
                    content_type = "video/quicktime";
                } else if (strstr(video_file, ".avi")) {
                    content_type = "video/x-msvideo";
                } else if (strstr(video_file, ".mkv")) {
                    content_type = "video/x-matroska";
                }
                
                // 检查范围请求头
                char *range_header = strstr(input_buf, "Range: ");
                if (range_header != NULL) {
                    range_header += 7; // 跳过 "Range: "
                    char *end_header = strstr(range_header, "\r\n");
                    if (end_header != NULL) {
                        *end_header = '\0';
                    }
                }
                
                send_video_with_range_support(client_fd, full_path, content_type, range_header);
            }
        }
    }
    // 处理根路径请求 - 返回HTML页面
    else if (strstr(input_buf, "GET / ") != NULL || strstr(input_buf, "GET /index.html") != NULL) {
        // 修复警告：使用正确的格式说明符
        size_t hello_len = video_player_html_len;
        size_t header_len = 256;
        size_t total_len = header_len + hello_len + 1;
        
        char *buf = (char *)malloc(total_len);
        if (buf == NULL) {
            perror("malloc");
            close(client_fd);
            return NULL;
        }
        
        snprintf(buf, total_len, 
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html; charset=utf-8\r\n"
            "Content-Length: %zu\r\n"
            "Connection: close\r\n"
            "\r\n"
            "%s", hello_len, video_player_html);
        
        ssize_t write_size = safe_write(client_fd, buf, strlen(buf));
        if (write_size < 0) {
            printf("Thread %lu: Failed to send HTML page\n", pthread_self());
        } else {
            printf("Thread %lu: HTML page sent: %zd bytes\n", pthread_self(), write_size);
        }
        
        free(buf);
    } else {
        // 其他请求返回404
        const char *not_found = 
            "HTTP/1.1 404 Not Found\r\n"
            "Content-Type: text/plain\r\n"
            "Connection: close\r\n"
            "\r\n"
            "404 Not Found";
        safe_write(client_fd, not_found, strlen(not_found));
        printf("Thread %lu: 404 Not Found\n", pthread_self());
    }
    
    close(client_fd);
    printf("Thread %lu: Client connection closed\n", pthread_self());
    return NULL;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        Usage();
        return 1;
    }
    
    // 设置信号处理，防止SIGPIPE导致程序退出
    setup_signal_handlers();
    
    // 初始化程序目录
    init_program_directory();
    
    // 检查videos目录是否存在，如果不存在则创建
    char videos_dir[PATH_MAX * 2];
    snprintf(videos_dir, sizeof(videos_dir), "%s/videos", program_dir);
    struct stat st;
    if (stat(videos_dir, &st) != 0) {
        printf("Creating videos directory: %s\n", videos_dir);
        mkdir(videos_dir, 0755);
    }
    
    printf("=== Mobile-Friendly Video Server Starting ===\n");
    printf("Program directory: %s\n", program_dir);
    printf("Binding to: %s:%s\n", argv[1], argv[2]);
    
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return 1;
    }
    
    int opt = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt");
        close(fd);
        return 1;
    }
    
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));
    
    int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0) {
        perror("bind");
        close(fd);
        return 1;
    }
    
    ret = listen(fd, 100);  // 增加backlog
    if (ret < 0) {
        perror("listen");
        close(fd);
        return 1;
    }
    
    printf("=== Mobile-Friendly Video Server Started Successfully ===\n");
    printf("Listening on %s:%s\n", argv[1], argv[2]);
    printf("Video directory: %s/videos/\n", program_dir);
    printf("Ready to accept connections...\n");
    
    int connection_count = 0;
    
    for (;;) {
        struct sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        int client_fd = accept(fd, (struct sockaddr *)&client_addr, &len);
        if (client_fd < 0) {
            perror("accept");
            continue;
        }
        
        connection_count++;
        
        // 打印客户端连接信息
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
        printf("[Connection #%d] New client from %s:%d\n", 
               connection_count, client_ip, ntohs(client_addr.sin_port));
        
        // 创建新线程处理客户端
        int *client_ptr = (int*)malloc(sizeof(int));
        if (client_ptr == NULL) {
            perror("malloc for client fd");
            close(client_fd);
            continue;
        }
        *client_ptr = client_fd;
        
        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_client, client_ptr) != 0) {
            perror("pthread_create");
            close(client_fd);
            free(client_ptr);
            printf("Failed to create thread for client #%d\n", connection_count);
        } else {
            pthread_detach(thread_id);  // 分离线程，自动回收资源
            printf("Client #%d assigned to thread %lu\n", connection_count, thread_id);
        }
        
        // 定期打印状态
        if (connection_count % 10 == 0) {
            printf("=== Server Status: Handled %d connections ===\n", connection_count);
        }
    }

    close(fd);
    return 0;
}